<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
# Copyright © 2009, 2010 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * Emails DMMailable objects.
 *
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
class DMMailer {

	/**
	 * Adapted from EmailAddressValidator::check_email_address() by Dave Child.
	 * Supposedly RFC2822-compliant.
	 *
	 * @param email
	 * @author Dave Child
	 * @see http://code.google.com/p/php-email-address-validation/
	 * @since 0.1
	 */
	public static function isValidEmail($email) {
		// Control characters are not allowed
		if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) {
			 return false;
		}

		// Split it into sections using last instance of "@"
		$intAtSymbol = strrpos($email, '@');
		if ($intAtSymbol === false) {
			 // No "@" symbol in email.
			 return false;
		}
		$arrEmailAddress[0] = substr($email, 0, $intAtSymbol);
		$arrEmailAddress[1] = substr($email, $intAtSymbol + 1);

		// Count the "@" symbols. Only one is allowed, except where
		// contained in quote marks in the local part. Quickest way to
		// check this is to remove anything in quotes.
		$arrTempAddress[0] = preg_replace('/"[^"]+"/'
													,''
													,$arrEmailAddress[0]);
		$arrTempAddress[1] = $arrEmailAddress[1];
		$strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
		// Then check - should be no "@" symbols.
		if (strrpos($strTempAddress, '@') !== false) {
			 // "@" symbol found
			 return false;
		}

		// Check local portion
		if (!self::isValidEmailUser($arrEmailAddress[0])) {
			 return false;
		}

		// Check domain portion
		if (!DMString::isValidHostname($arrEmailAddress[1])) {
			 return false;
		}

		// If we're still here, all checks above passed. Email is valid.
		return true;
	}

	/**
	 * Adapted from EmailAddressValidator::check_local_portion() by Dave Child.
	 * Supposedly RFC2822-compliant.
	 *
	 * @param str
	 * @author Dave Child
	 * @see http://code.google.com/p/php-email-address-validation/
	 * @see DMMailer::isValidEmail()
	 * @since 0.1
	 */
	private static final function isValidEmailUser($str) {
		// Local portion can only be from 1 to 64 characters, inclusive.
		// Please note that servers are encouraged to accept longer local
		// parts than 64 characters.
		if ((strlen($str) < 1) || (strlen($str) > 64)) {
			 return false;
		}
		// Local portion must be:
		// 1) a dot-atom (strings separated by periods)
		// 2) a quoted string
		// 3) an obsolete format string (combination of the above)
		$arrLocalPortion = explode('.', $str);
		for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
			  if (!preg_match('.^('
								  .    '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
								  .    '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
								  .'|'
								  .    '("[^\\\"]{0,62}")'
								  .')$.'
								  ,$arrLocalPortion[$i])) {
				  return false;
			 }
		}
		return true;
	}

	/**
	 * @param DMMailable mailable
	 * @return Return value of the PHP mail() function
	 * @throws DMInvalidEmailException
	 * @since 2.0
	 */
	public function send(DMMailable $mailable) {
		if (!self::isValidEmail($mailable->getEmailRecipientEmail())) {
			throw new DMInvalidEmailException($mailable);
		}
		return mail(
				$mailable->getEmailRecipientEmail(),
				$mailable->getEmailSubject(),
				wordwrap($mailable->getEmailBody(), 75),
				$this->getHeaders($mailable));
	}

	private function getHeaders(DMMailable $mailable) {
		$from = null;
		$headers = null;
		if ($mailable->getEmailFromEmail()) {
			$from = $mailable->getEmailFromEmail();
		}
		if ($from) {
			if ($mailable->getEmailFromName()) {
				$from = sprintf('"%s" <%s>',
						$mailable->getEmailFromName(), $from);
			}
			$headers = sprintf("From: %s \r\n", $from);
		}
		return $headers;
	}

	/**
	 * @param DMComment comment
	 * @return DMEmailMessage
	 */
	public function sendNotificationOfNewComment(DMComment $comment) {
		$e = new DMEmailMessage();
		$e->setEmailRecipientEmail(
			DMConfigXML::getInstance()->getCommentNotificationEmail());
		$body = sprintf(
			"From: %s%s\n\n"
			. "%s\n\n"
			. "Log into the Control Panel to moderate this comment:\n"
			. "%s\n",
			DMString::websafe($comment->getName()),
			(DMString::websafe($comment->getEmail()))
				? " (" . DMString::websafe($comment->getEmail()) . ")" : "",
			DMString::websafe($comment->getValue()),
			DMInternalURI::getURIWithParams("admin")
		);
		$e->setEmailBody($body);
		$e->setEmailSubject(
				DMLocalizedString::getString('EMAIL_COMMENT_SUBJECT'));
		return $this->send($e);
	}

}

